第15章 关联分析: Apriori算法¶

这一章介绍一个常用于挖掘不同数据之间关联关系的经典算法--Apriorr算法, 并利用该算法进行病症关联规则分析

15.1 关联分析的基本概念和Apriori算法¶

关联分析通过分析数据集, 寻找事物间的关联性, 挖掘频繁出现的组合, 并描述组合内对象同时出现的模式和规律

比如, 对超市购物的数据进行关联分析, 通过发现顾客所购买的不同商品之间的关系, 分析顾客的购买习惯, 设计商品的组合摆放位置, 制定相应的营销策略, 从而制造需求, 提高销售额, 创造额外收入, 和上一章介绍的协同过滤算法一样, 关联分析技术也可以应用于智能推荐系统, 当我们挖掘出频繁出现的组合和强关联规则之后, 就可以通过强关联规则为顾客推荐商品

15.1.1 关联分析的基本概念¶

先通过一组简单的交易数据演示关联分析的基本概念:

  • 表中为一组购物篮数据, 目的是通过该表来挖掘不同商品间的关联关系

    image.png

    在分析开始前, 了解关联分析的一些基本概念

    • 事务库: 上表中的购物篮数据就是一个事务库, 该事务库记录的是用户行为的数据

    • 实务: 事务库中的每一条记录称为一笔实务, 在上表的购物篮事务库中, 一笔事务就是一次购物行为, 比如第一行数据 "用户1购买商品A,B,C" 即为一笔数据

    • 项和项集: 在购物篮事务库中, 每样商品为一个项, 项的集合称为项集, 例如 "A,B" "A,C" "A,B,C" 等, 都是项集, 即不同商品的组合

    然后是关联学习中的核心概念, 包括关联规则、支持度、频繁项集、置信度和强关联规则, 之后的所有分析都是基于这些概念展开的

    • 关联规则: 关联规则是形如 A → B 的表达式, A称为前件, B称为后件, 即一个用户购买了商品A, 则也会购买商品B, 这里的A和B不是指单一的商品, 而是指项集, 比如, {A,B} → {C} 的含义就是一个用户如果购买了商品A和商品B, 则也会购买商品C

    • 支持度: 项集的支持度定义为包含该项集的事务在所有实务中所占的比例, 例如, 项集 {A,B} 在购物篮实务中共出现3次(第1,2,4条数据), 而整个事务库一共有5笔实务(即五条数据), 因此它的支持度为 $3 \div 5 = 60\%$

    • 频繁项集: 支持度大于等于认为设定的阈值(该阈值称为最小支持度)的项集, 比如, 将最小支持度设为 50%, 因为上面得到项集{A,B}的支持度为60%, 所以它是频繁项集, 也就是说, 该项集在所有食物中出现得较为频繁

    • 置信度: 置信度的含义是项集Y在包含项集X的事务中出现的频繁程度, 在购物篮事务库中, 关联规则X→Y的置信度为在购买项集X的基础上购买项集Y的概率 $P(Y|X)$, 计算公式为:

      $$ P(Y|X) = \frac{P(XY)}{P(X)} $$

    以上述的购物篮事务库为例, 关联规则 {A,B} → {C} 的置信度计算公式为:

    $$ P(\{C\} | \{A,B\}) = \frac{P(\{A,B,C\})}{P(\{A,B\})} $$

    项集 {A,B,C} 在所有5笔事务中总共出现2次(第1,4笔事务), 所以 P({A,B,B}) = 2/5; 项集 {A,B} 在所有5笔事务中总共出现3次, (第1,2,4笔事务), 所以 P({A,B}) = 3/5, 代入公式可得:

    $$ P(\{C\} | \{A,B\}) = \frac{P(\{A,B,C\})}{P(\{A,B\})} = \frac{2/5}{3/5} = \frac{2}{3} = 0.67 $$

    熟悉公式后容易发现分母其实都是一样的, 所以可以直接用项集出现次数作比

    这个结果说明购买了商品A和商品B的人中有67% 的人也购买了商品C, 该概率还是比较高的, 因此, 商场可以向购买了商品A和商品B的人推荐商品C, 如可以将这3种商品放得比较近

    • 强关联规则: 在实际应用中, 通常是先寻找满足最小支持度的频繁项集, 然后再频繁项集中寻找满足最小置信度的关联规则, 这样的关联规则称为强关联规则, 即我们需要的关联规则

15.1.2 Apriori算法的数学演示¶

这节讲解经典的关联规则挖掘算法--Apriori算法的基本思路, 并针对上节的购物篮事务库进行具体演算

  1. 基本思路

    关联分析的最终目标是要找出强关联规则, 以针对目标客户推荐商品

    Apriori算法是最著名的关联规则的挖掘算法之一, 其核心是一种递推算法, Apriori算法的步骤有:

    • 步骤1: 设定最小支持度和最小置信度

    • 步骤2: 根据最小支持度找出所有的频繁项集

    • 步骤3: 根据最小置信度发现强关联规则

  2. 案例演示

    image.png

    • 步骤1: 设定最小支持度和最小置信度

      首先设定最小支持度为2/5, 即40%; 最小置信度为4/5, 即80%

    • 步骤2: 根据最小支持度找出所有的频繁项集

      这一步是关联分析中较为重要的一个环节, 我们需要找到所有的频繁项集, 因为强关联规则都是从频繁项集中产生的

      比如, 项集{A, B, C, D}只出现了1次, 支持度为1/5, 小于最小支持度2/5, 该项集就不是频繁项集, 这就意味着很难从该项集中挖掘出类似{A, B, C}→{D}的强关联规则, 即类似“购买了商品A、B、C的用户也会购买商品D”这样的规则, 而项集{B, C}出现了4次, 支持度为4/5, 大于最小支持度2/5, 该项集就属于频繁项集, 即商品B和商品C经常同时出现, 因此很有可能挖掘出{B}→{C}这样的强关联规则(当然还需要经过步骤3的最小置信度检验), 即购买了商品B的用户也会购买商品C, 这样就可以向购买了商品B的用户推荐商品C

      那么该如何快速找到所有的频繁项集呢?最简单的方法就是列出所有项集, 然后计算它们的支持度, 如果大于等于最小支持度则认定为频繁项集, 但是列出所有项集意味着要列出所有的排列组合, 如果数据量较大, 则会造成巨大的计算量

      Apriori算法采用了一个精巧的思路来加快运算速度:先计算长度为1的项集, 然后挖掘其中的频繁项集;再将长度为1的频繁项集进行排列组合, 从中挖掘长度为2的频繁项集, 依此类推。其核心逻辑是一个迭代判断的思想:如果连长度为n-1的项集都不是频繁项集, 那么就不用考虑长度为n的项集了, 也就是说, 如果在迭代的过程中发现{A, B, C}不是频繁项集, 那么{A, B, C, D}必然不是频繁项集, 也就不用去考虑它了

      演示一下具体的数学演算过程:

      • 首先计算长度为1的候选项集, 扫描购物篮事务库, 统计每种商品出现的次数, 结果见下:

        image-2.png

        因为每种商品的支持度都大于或等于最小支持度2/5, 所以无需删减, 直接保留候选项集作为长度为1的频繁项集

        将长度为1的频繁项集进行两两组合, 形成长度为2的候选项集, 扫描购物篮事务库, 统计各个候选项集出现的次数, 结果见下:

        image-3.png

        因为项集{A,D}的支持度小于1/5, 小于最小支持度, 所以从候选项集中删减掉该项集, 得到长度为2的所有频繁项集, 结果见下:

        image-4.png

        将长度为2的频繁项集进行两两组合, 形成长度为3的候选项集, 扫描购物篮事务库, 统计各个候选项集出现的次数, 结果见下:

        image-5.png image-6.png

        因为项集{A, B, D}和项集{A, C, D}的支持度为1/5, 小于最小支持度, 所以从候选项集中删减掉这2个项集, 得到长度为3的所有频繁项集, 结果见下:

        image-7.png

        将长度为3的频繁项集进行两两组合, 形成长度为4的候选项集, 扫描购物篮事务库, 统计候选项集出现的次数, 结果见下:

        image-8.png

        因为项集{A, B, C, D}的支持度为1/5, 小于最小支持度, 所以从候选项集中删减掉这个项集, 此时长度为4的频繁项集集合为空, 至此便生成了所有的频繁项集

        因为关联规则要在至少2个数据之间才可能存在, 所以我们需要选择长度大于1的频繁项集, 见下:

        image-9.png

    • 步骤3: 根据最小置信度发现强相关关联规则

      找到所有长度大于1的频繁项集后, 强关联规则就很有可能就从这些频繁项集中产生, 此时最后一个步骤就是从各个频繁项集中推导出所有可能的关联规则, 再利用最小置信度来检验这些关联规则是否为强关联规则

      举例来说, 频繁项集{A, B, C}的非空子集有{A}、{B}、{C}、{A, B}、{A, C}、{B, C}, 由此可以推导出6条关联规则

      根据15.1.1的公式对这些关联规则分别计算置信度并与最小置信度进行比较, 见下:

      image-10.png

      注意置信度计算中分子都为2, 是项集{A, B, C}在所有事务中出现的次数, 分母则是非空子集在所有事务中出现的次数, 如规则1中的分母3, 即{A, B}在所有事务中出现的次数

      从上表可知, 只有规则2满足最小置信度要求, 所以得到一条强关联规则{A, C}→{B}

      对每个长度大于1的频繁项集进行类似操作, 可推导出所有强关联规则, 见下表:

      image-11.png

      至此, 我们便得到了9条强关联规则。以第1条强关联规则{A, C}→{B}为例, 我们便可以向购买了商品A和商品C的用户推荐商品B, 其余依此类推

15.1.3 Apriori算法的代码实现¶

在Python中可以利用apyori库和mlxtend库快速推导强关联规则

apyori库是一个经典的库, 它使用起来较为简单, 不过有时会漏掉一些强关联规则;mlxtend库的使用稍显麻烦, 但是它能捕捉到所有的强关联规则

1. 通过apyori库实现Apriori算法¶

In [1]:
# apyori库的安装:将下面代码注释取消后运行
# !pip install apyori
In [2]:
transactions = [['A', 'B', 'C'], ['A', 'B'], ['B', 'C'], ['A', 'B', 'C', 'D'], ['B', 'C', 'D']]

transactions
Out[2]:
[['A', 'B', 'C'],
 ['A', 'B'],
 ['B', 'C'],
 ['A', 'B', 'C', 'D'],
 ['B', 'C', 'D']]
In [3]:
from apyori import apriori
rules = apriori(transactions, min_support=0.4, min_confidence=0.8) # in_support参数为最小支持度, 这里设置为0.4, 即之前设定的40%, min_confidence参数为最小置信度, 这里设置为0.8, 即之前设定的80%
results = list(rules) # 将获取到的关联规则赋给变量rules
In [4]:
results
Out[4]:
[RelationRecord(items=frozenset({'B'}), support=1.0, ordered_statistics=[OrderedStatistic(items_base=frozenset(), items_add=frozenset({'B'}), confidence=1.0, lift=1.0)]),
 RelationRecord(items=frozenset({'C'}), support=0.8, ordered_statistics=[OrderedStatistic(items_base=frozenset(), items_add=frozenset({'C'}), confidence=0.8, lift=1.0)]),
 RelationRecord(items=frozenset({'A', 'B'}), support=0.6, ordered_statistics=[OrderedStatistic(items_base=frozenset({'A'}), items_add=frozenset({'B'}), confidence=1.0, lift=1.0)]),
 RelationRecord(items=frozenset({'B', 'C'}), support=0.8, ordered_statistics=[OrderedStatistic(items_base=frozenset(), items_add=frozenset({'B', 'C'}), confidence=0.8, lift=1.0), OrderedStatistic(items_base=frozenset({'B'}), items_add=frozenset({'C'}), confidence=0.8, lift=1.0), OrderedStatistic(items_base=frozenset({'C'}), items_add=frozenset({'B'}), confidence=1.0, lift=1.0)]),
 RelationRecord(items=frozenset({'D', 'B'}), support=0.4, ordered_statistics=[OrderedStatistic(items_base=frozenset({'D'}), items_add=frozenset({'B'}), confidence=1.0, lift=1.0)]),
 RelationRecord(items=frozenset({'D', 'C'}), support=0.4, ordered_statistics=[OrderedStatistic(items_base=frozenset({'D'}), items_add=frozenset({'C'}), confidence=1.0, lift=1.25)]),
 RelationRecord(items=frozenset({'A', 'B', 'C'}), support=0.4, ordered_statistics=[OrderedStatistic(items_base=frozenset({'A', 'C'}), items_add=frozenset({'B'}), confidence=1.0, lift=1.0)]),
 RelationRecord(items=frozenset({'D', 'B', 'C'}), support=0.4, ordered_statistics=[OrderedStatistic(items_base=frozenset({'D'}), items_add=frozenset({'B', 'C'}), confidence=1.0, lift=1.25), OrderedStatistic(items_base=frozenset({'D', 'B'}), items_add=frozenset({'C'}), confidence=1.0, lift=1.25), OrderedStatistic(items_base=frozenset({'D', 'C'}), items_add=frozenset({'B'}), confidence=1.0, lift=1.0)])]
In [5]:
type(results[0].ordered_statistics)
Out[5]:
list
In [6]:
for i in results:  # 遍历results中的每一个频繁项集
    for j in i.ordered_statistics:  # 获取频繁项集中的关联规则
        X = j.items_base  # 关联规则的前件
        Y = j.items_add  # 关联规则的后件
        x = ', '.join([item for item in X])  # 连接前件中的元素
        y = ', '.join([item for item in Y])  # 连接后件中的元素
        if x != '':  # 防止出现关联规则前件为空的情况
            print(x + ' → ' + y)  # 通过字符串拼接的方式更好呈现结果
A → B
B → C
C → B
D → B
D → C
A, C → B
D → B, C
D, B → C
D, C → B

2. 通过mlxtend库实现Apriori算法¶

In [7]:
# !pip install mlxtend

# 或者

# !pip install mlxtend -i https://pypi.tuna.tsinghua.edu.cn/simple
In [8]:
transactions = [['A', 'B', 'C'], ['A', 'B'], ['B', 'C'], ['A', 'B', 'C', 'D'], ['B', 'C', 'D']]

transactions
Out[8]:
[['A', 'B', 'C'],
 ['A', 'B'],
 ['B', 'C'],
 ['A', 'B', 'C', 'D'],
 ['B', 'C', 'D']]
In [9]:
from mlxtend.preprocessing import TransactionEncoder
TE = TransactionEncoder()  # 构造转换模型
data = TE.fit_transform(transactions)  # 将原始数据转换为bool值
In [10]:
data
Out[10]:
array([[ True,  True,  True, False],
       [ True,  True, False, False],
       [False,  True,  True, False],
       [ True,  True,  True,  True],
       [False,  True,  True,  True]])
In [11]:
# 通过在内容后面加?可以查看官方介绍
TE.columns_?
Type:        list
String form: ['A', 'B', 'C', 'D']
Length:      4
Docstring:  
Built-in mutable sequence.

If no argument is given, the constructor creates a new empty list.
The argument must be an iterable if specified.
In [12]:
import pandas as pd
df = pd.DataFrame(data, columns=TE.columns_)  # 用DataFrame存储bool数据

df
Out[12]:
A B C D
0 True True True False
1 True True False False
2 False True True False
3 True True True True
4 False True True True
In [13]:
from mlxtend.frequent_patterns import apriori
items = apriori(df, min_support=0.4, use_colnames=True)  # use_colnames=True表示使用df的列名而不是列索引作为返回的DataFrame列名
In [14]:
items 
Out[14]:
support itemsets
0 0.6 (A)
1 1.0 (B)
2 0.8 (C)
3 0.4 (D)
4 0.6 (A, B)
5 0.4 (A, C)
6 0.8 (B, C)
7 0.4 (D, B)
8 0.4 (D, C)
9 0.4 (A, B, C)
10 0.4 (D, B, C)
In [15]:
items['itemsets'].apply(lambda x: len(x))  # 获取每一个项集的元素个数
Out[15]:
0     1
1     1
2     1
3     1
4     2
5     2
6     2
7     2
8     2
9     3
10    3
Name: itemsets, dtype: int64
In [16]:
items[items['itemsets'].apply(lambda x: len(x)) >= 2]  # 选择长度 >=2 的频繁项集
Out[16]:
support itemsets
4 0.6 (A, B)
5 0.4 (A, C)
6 0.8 (B, C)
7 0.4 (D, B)
8 0.4 (D, C)
9 0.4 (A, B, C)
10 0.4 (D, B, C)
In [17]:
import warnings

warnings.filterwarnings('ignore')
In [18]:
# 根据最小置信度在频繁项集中产生强关联规则
from mlxtend.frequent_patterns import association_rules
rules = association_rules(items, min_threshold=0.8)
In [19]:
rules
Out[19]:
antecedents consequents antecedent support consequent support support confidence lift representativity leverage conviction zhangs_metric jaccard certainty kulczynski
0 (A) (B) 0.6 1.0 0.6 1.0 1.00 1.0 0.00 inf 0.000000 0.6 0.0 0.80
1 (B) (C) 1.0 0.8 0.8 0.8 1.00 1.0 0.00 1.0 0.000000 0.8 0.0 0.90
2 (C) (B) 0.8 1.0 0.8 1.0 1.00 1.0 0.00 inf 0.000000 0.8 0.0 0.90
3 (D) (B) 0.4 1.0 0.4 1.0 1.00 1.0 0.00 inf 0.000000 0.4 0.0 0.70
4 (D) (C) 0.4 0.8 0.4 1.0 1.25 1.0 0.08 inf 0.333333 0.5 1.0 0.75
5 (A, C) (B) 0.4 1.0 0.4 1.0 1.00 1.0 0.00 inf 0.000000 0.4 0.0 0.70
6 (D, B) (C) 0.4 0.8 0.4 1.0 1.25 1.0 0.08 inf 0.333333 0.5 1.0 0.75
7 (D, C) (B) 0.4 1.0 0.4 1.0 1.00 1.0 0.00 inf 0.000000 0.4 0.0 0.70
8 (D) (B, C) 0.4 0.8 0.4 1.0 1.25 1.0 0.08 inf 0.333333 0.5 1.0 0.75

antecedents列代表关联规则中的前件, 如关联规则{A}→{B}中的{A};

consequents列代表关联规则中的后件, 如关联规则{A}→{B}中的{B};

antecedent support列代表前件的支持度, 例如, A共出现3次(共5笔事务), 所以关联前件支持度为3/5=0.6;

consequent support列代表后件的支持度, 例如, B共出现5次, 所以关联后件支持度为5/5=1;

support列代表该关联规则的支持度, 例如, {A, B}共出现3次, 所以关联规则的支持度为3/5=0.6;

confidence列代表该关联规则的置信度, 除了用15.1.1小节中的公式计算外, 还可以用“关联规则支持度/前件支持度”来计算

$$ conf(\{A\} \rightarrow \{B\}) = \frac{support(\{A,B\})}{support(A)} $$

补充知识点: lift(提升度)、leverage(杠杆率)、conviction(确信度)¶

输出结果中的lift、leverage、conviction这3列都是用来衡量关联度强弱的

  • lift列代表该关联规则的提升度, 其计算公式为 "关联规则支持度/(前件支持度 × 后件支持度)", 值越大, 表明A和B的关联度越强

    $$ lift(\{A\} \rightarrow \{B\}) = \frac{support(\{A,B\})}{support(A)\times support(B)} $$

  • leverage列代表关联规则的杠杆率, 其计算公式为 "关联规则支持度 - 前件支持度×后件支持度", 该值越大, 表明A和B的关联度越强

    $$ leverage(\{A\}\rightarrow \{B\}) = support(\{A,B\}) - support(A) \times support(B) $$

  • conviction列代表关联规则的确信度, 其计算公式为 "(1 - 后件支持度)/(1 - 关联规则置信度)", 该值越大, 表明A和B的关联度越强

    $$ conv(\{A\} \rightarrow \{B\}) = \frac{1 - support(B)}{conf(\{A\} \rightarrow \{B\})} $$

In [20]:
# 通过如下代码更好地展示关联规则
for i, j in rules.iterrows():  # 遍历DataFrame二维表格的每一行
    X = j['antecedents']  # 关联规则的前件
    Y = j['consequents']  # 关联规则的后件
    x = ', '.join([item for item in X])  # 连接前件中的元素
    y = ', '.join([item for item in Y])  # 连接后件中的元素
    print(x + ' → ' + y)  # 通过字符串拼接打印关联规则
A → B
B → C
C → B
D → B
D → C
A, C → B
D, B → C
D, C → B
D → B, C

总体来说, 通过apyori库和mlxtend库都能方便地进行关联规则分析, 在实际应用中, 两者的差别并不大

如果追求简便性, 推荐使用apyori库;如果想获得更严谨的结果, 则推荐使用mlxtend库

15.2 案例实战: 病症关联规则分析¶

15.2.1 案例背景¶

假设有一种医学理论认为, 五脏和一些病症之间存在关联关系, 见下表:

image.png

例如, 如果一个人的脾出了问题, 那么他身上除了会表现出与脾关联的便秘病症, 很可能还会伴随着消化不良的病症

该医学理论还认为, 我们的五脏六腑不是一个个独立的脏器, 而是相互联系、相互影响的。有时某一个脏器出了问题, 会影响其关联的脏器, 患者身上就会同时表现出这两种脏器的关联病症, 例如, 一个患者感到腰疼或者有脱发现象(肾的关联病症), 很可能就会伴有眼干或易怒等病症(肝的关联病症)

本案例的目标就是通过Apriori算法对病症数据进行分析, 挖掘病症之间的关联关系

15.2.2 代码实现¶

利用apyori库和mlxtend库来编写代码前, 需要读取数据并进行简单的预处理, 因为这两个库可处理的都是如下所示的双重列表结构, 而用pandas库读取Excel工作簿时得到的是DataFrame格式的数据结构, 所以需要进行转换

In [21]:
transactions = [['A', 'B', 'C'], ['A', 'B'], ['B', 'C'], ['A', 'B',  'C', 'D'], ['B', 'C', 'D']]

transactions
Out[21]:
[['A', 'B', 'C'],
 ['A', 'B'],
 ['B', 'C'],
 ['A', 'B', 'C', 'D'],
 ['B', 'C', 'D']]
In [22]:
import pandas as pd
df = pd.read_excel('中医辨证.xlsx')

df.head()
Out[22]:
病人编号 病人症状
0 1 消化不良,便秘
1 2 心悸,失眠
2 3 腰疼,脱发,眼干
3 4 腹胀,便秘,哮喘,胸闷气短,消化不良
4 5 神经衰弱,失眠,月经不调
In [23]:
# 简单演示下tolist()函数
print(df['病人症状'].tolist()[0:10])

print(len(df['病人症状']))
['消化不良,便秘', '心悸,失眠', '腰疼,脱发,眼干', '腹胀,便秘,哮喘,胸闷气短,消化不良', '神经衰弱,失眠,月经不调', '神经衰弱,消化不良,月经不调', '失眠,眼干,月经不调', '腹胀,便秘,哮喘,胸闷气短,消化不良', '腰疼,脱发,眼干,心悸', '神经衰弱,消化不良,月经不调']
1000
In [24]:
# 转换为双重列表结构
symptoms = []
for i in df['病人症状'].tolist():
    symptoms.append(i.split(','))
In [25]:
print(symptoms[0:10])
[['消化不良', '便秘'], ['心悸', '失眠'], ['腰疼', '脱发', '眼干'], ['腹胀', '便秘', '哮喘', '胸闷气短', '消化不良'], ['神经衰弱', '失眠', '月经不调'], ['神经衰弱', '消化不良', '月经不调'], ['失眠', '眼干', '月经不调'], ['腹胀', '便秘', '哮喘', '胸闷气短', '消化不良'], ['腰疼', '脱发', '眼干', '心悸'], ['神经衰弱', '消化不良', '月经不调']]

1. 通过apyori库实现¶

In [26]:
from apyori import apriori
rules = apriori(symptoms, min_support=0.1, min_confidence=0.7)
results = list(rules)
In [27]:
for i in results:  # 遍历results中的每一个频繁项集
    for j in i.ordered_statistics:  # 获取频繁项集中的关联规则
        X = j.items_base  # 关联规则的前件
        Y = j.items_add  # 关联规则的后件
        x = ', '.join([item for item in X])  # 连接前件中的元素
        y = ', '.join([item for item in Y])  # 连接后件中的元素
        if x != '':  # 防止出现关联规则前件为空的情况
            print(x + ' → ' + y)  # 通过字符串拼接的方式更好呈现结果
便秘 → 消化不良
失眠 → 月经不调
神经衰弱 → 消化不良
脱发 → 眼干
腰疼 → 眼干
心悸, 失眠 → 月经不调
神经衰弱, 心悸 → 消化不良

2. 通过mlxtend实现¶

In [28]:
from mlxtend.preprocessing import TransactionEncoder
TE = TransactionEncoder()  # 构造转换模型
data = TE.fit_transform(symptoms)  # 将原始数据转化为bool值
data
Out[28]:
array([[ True, False, False, ..., False, False, False],
       [False, False,  True, ..., False, False, False],
       [False, False, False, ...,  True, False, False],
       ...,
       [False, False, False, ..., False, False,  True],
       [False, False, False, ..., False, False, False],
       [False,  True, False, ..., False, False, False]])
In [29]:
import pandas as pd
df = pd.DataFrame(data, columns=TE.columns_)  # 用DataFrame存储bool数据
df.head()
Out[29]:
便秘 哮喘 失眠 心悸 易怒 月经不调 消化不良 眼干 神经衰弱 耳鸣耳聋 胸闷气短 脱发 腰疼 腹胀 鼻炎
0 True False False False False False True False False False False False False False False
1 False False True True False False False False False False False False False False False
2 False False False False False False False True False False False True True False False
3 True True False False False False True False False False True False False True False
4 False False True False False True False False True False False False False False False
In [30]:
from mlxtend.frequent_patterns import apriori # 将数据处理为mlxtend库可接受的特定格式后, 从mlxtend库的frequent_patterns模块中引入apriori()函数来挖掘数据中的频繁项集
items = apriori(df, min_support=0.1, use_colnames=True)
In [31]:
items
Out[31]:
support itemsets
0 0.184 (便秘)
1 0.124 (哮喘)
2 0.393 (失眠)
3 0.452 (心悸)
4 0.484 (月经不调)
5 0.344 (消化不良)
6 0.311 (眼干)
7 0.188 (神经衰弱)
8 0.140 (胸闷气短)
9 0.151 (脱发)
10 0.160 (腰疼)
11 0.160 (消化不良, 便秘)
12 0.218 (心悸, 失眠)
13 0.318 (月经不调, 失眠)
14 0.116 (失眠, 眼干)
15 0.249 (月经不调, 心悸)
16 0.180 (消化不良, 心悸)
17 0.114 (心悸, 眼干)
18 0.108 (神经衰弱, 心悸)
19 0.104 (月经不调, 消化不良)
20 0.170 (月经不调, 眼干)
21 0.164 (神经衰弱, 消化不良)
22 0.143 (脱发, 眼干)
23 0.136 (腰疼, 眼干)
24 0.167 (月经不调, 心悸, 失眠)
25 0.100 (神经衰弱, 消化不良, 心悸)
In [32]:
items[items['itemsets'].apply(lambda x: len(x)) >= 2]
Out[32]:
support itemsets
11 0.160 (消化不良, 便秘)
12 0.218 (心悸, 失眠)
13 0.318 (月经不调, 失眠)
14 0.116 (失眠, 眼干)
15 0.249 (月经不调, 心悸)
16 0.180 (消化不良, 心悸)
17 0.114 (心悸, 眼干)
18 0.108 (神经衰弱, 心悸)
19 0.104 (月经不调, 消化不良)
20 0.170 (月经不调, 眼干)
21 0.164 (神经衰弱, 消化不良)
22 0.143 (脱发, 眼干)
23 0.136 (腰疼, 眼干)
24 0.167 (月经不调, 心悸, 失眠)
25 0.100 (神经衰弱, 消化不良, 心悸)
In [33]:
# 根据最小置信度在频繁项集中挖掘强相关规则

from mlxtend.frequent_patterns import association_rules
rules = association_rules(items, min_threshold=0.7)
In [34]:
rules
Out[34]:
antecedents consequents antecedent support consequent support support confidence lift representativity leverage conviction zhangs_metric jaccard certainty kulczynski
0 (便秘) (消化不良) 0.184 0.344 0.160 0.869565 2.527806 1.0 0.096704 5.029333 0.740686 0.434783 0.801166 0.667341
1 (失眠) (月经不调) 0.393 0.484 0.318 0.809160 1.671819 1.0 0.127788 2.703840 0.662025 0.568873 0.630156 0.733093
2 (神经衰弱) (消化不良) 0.188 0.344 0.164 0.872340 2.535873 1.0 0.099328 5.138667 0.745885 0.445652 0.805397 0.674542
3 (脱发) (眼干) 0.151 0.311 0.143 0.947020 3.045080 1.0 0.096039 13.004875 0.791050 0.448276 0.923106 0.703413
4 (腰疼) (眼干) 0.160 0.311 0.136 0.850000 2.733119 1.0 0.086240 4.593333 0.754902 0.405970 0.782293 0.643650
5 (心悸, 失眠) (月经不调) 0.218 0.484 0.167 0.766055 1.582758 1.0 0.061488 2.205647 0.470833 0.312150 0.546618 0.555548
6 (神经衰弱, 心悸) (消化不良) 0.108 0.344 0.100 0.925926 2.691645 1.0 0.062848 8.856000 0.704574 0.284091 0.887082 0.608312
In [35]:
for i, j in rules.iterrows():  # 遍历DataFrame二维表格的每一行
    X = j['antecedents']  # 关联规则的前件
    Y = j['consequents']  # 关联规则的后件
    x = ', '.join([item for item in X])  # 连接前件中的元素
    y = ', '.join([item for item in Y])  # 连接后件中的元素
    print(x + ' → ' + y)  # 通过字符串拼接打印关联规则
便秘 → 消化不良
失眠 → 月经不调
神经衰弱 → 消化不良
脱发 → 眼干
腰疼 → 眼干
心悸, 失眠 → 月经不调
神经衰弱, 心悸 → 消化不良

从数据分析的角度来看, 不同病症之间存在一定的关联关系

总结来说, Apriori算法是用于关联分析的一个经典算法, 它不仅可以应用于电商领域的商品推荐和医疗领域的病症关联分析, 还可以应用于金融产品的交叉销售, 即如何组合销售关联关系较强的金融产品, 从而创造更高的经济收益, 其思路和本章的案例实战基本一致